TCP (Transmission Control Protocol)

  • A reliable communication protocol that guarantees the delivery of data packets between two devices.

  • It is part of the TCP/IP  suite and is used by many protocols such as HTTP, HTTPS, FTP, etc.

  • Godot:

    • "TCP ensures packets will always arrive reliably and in order, but latency is generally higher due to error correction. It's also quite a complex protocol because it understands what a "connection" is, and optimizes for goals that often don't suit applications like multiplayer games. Packets are buffered to be sent in larger batches, trading less per-packet overhead for higher latency. This can be useful for things like HTTP, but generally not for games. Some of this can be configured and disabled (e.g. by disabling "Nagle's algorithm" for the TCP connection)."

Protocol

  • SYN -> SYN ACK -> ACK.

  • .

  • TCP packets do not contain a reliable sender ID that can be verified directly.

Closing ( close )

  • The socket's file descriptor (e.g., sockfd ) is marked as available for reuse.

  • Decrements the reference count for the socket.

    • Sockets may have multiple references (e.g., via dup() , fork() , or threading).

    • Resources are only freed (e.g., memory, kernel structures) when the reference count reaches zero.

  • It initiates connection teardown (sends FIN  if it’s the last reference).

  • The integer value representing the descriptor can now be reassigned by future socket() , open() , or similar calls.

  • The client cannot close the connection to the server; it's impossible. Reasons:

    • The client doesn't have the server socket available to it.

      • The client has no way to reference the server’s socket.

    • While TCP connections are bidirectional (peer-to-peer), socket descriptors are local to each process.

      • The client and server communicate via IP:Port pairs, but their socket file descriptors ( sockfd ) are private.

      • The kernel enforces this separation for security and stability.

    • Even if the client sends malicious packets (e.g., a spoofed RST ), the server’s OS will handle it at the TCP layer, not the application socket layer.

  • The only way  the server’s socket closes is if:

    1. The server explicitly calls close()  on its socket.

    2. The server process crashes (kernel cleans up resources).

    3. The OS terminates the process (e.g., kill -9 ).

Shutdown ( shutdown )

  • Forces a partial or full closure of communication in a specified direction.

  • Does not free the socket descriptor (still needs close()  later).

  • Immediately affects the TCP connection state (sends FIN  or RST ).

Connection

  • Server :

    • listen

      • Puts the socket into passive mode, indicating it will accept connections.

      • “I am ready to accept TCP connections.”

      • Necessary before: accept .

      • Relevant only for TCP (stream) sockets, not UDP.

      • Internally does a bind .

    • bind

      • Associates the socket with a local address (IP + port).

      • “I want to use this IP:port for this socket.”

    • accept

      • In Odin , the accept()  call on a TCP socket is blocking by default, meaning execution halts until a client tries to connect to the socket.

        • Blocks until a client does dial()  to that address/port.

        • Non-blocking mode :

          • You need to configure the socket with system flags, usually requiring a direct OS syscall (not abstracted by default in core:net ).

          • Alternatively, use select , poll , or threads/coroutines to handle multiple connections concurrently.

  • Client :

    • dial

      • Establishes an active connection with a remote server.

      • Connects to an IP + port that is listening.

Security

  • Sender identification :

    • The remote IP and port can be read with conn.RemoteAddr() , but:

      • This can be forged in MITM attacks  if no encryption is present.

      • Even with IP/port, identity is not guaranteed  (e.g., NAT, spoofing, etc.).

    • In Godot:

      • The peer_id is sent along with the packet.

      • This would be extremely insecure if it weren’t for a supposed  verification between the sender peer_id and its address upon receiving a packet.

        • If the peer_id and address do not match the stored value in a hashmap, it is an attempted forgery.

      • This is completely insecure if the peer_id and address are forged simultaneously, in a spoofing attack.

      • In this case, encryption is required.

  • "Double listen"

    • "If a legitimate server is doing listen  on an IP:port, is it possible for another computer (a remote attacker) to also listen  on the same IP:port to intercept connections?"

    • Routers/Internet/DNS/etc will forward packets only to the host that has the corresponding public IP.

    • Example :

      • The legitimate server is at 192.168.1.100:8080 .

      • An attacker on another host (e.g., 192.168.1.250 ) tries to listen  also on 0.0.0.0:8080 .

      • Result:

        • The attacker only receives connections sent to its own local IP.

          • Connections sent to the legitimate server IP still go to 192.168.1.100, as IP routing determines.

    • Cases where the attack may work :

      • Involve network manipulation.

      • ARP spoofing / ARP poisoning (LAN)

        • The attacker impersonates the "server IP" on the local network.

        • If successful, LAN clients may redirect packets to them.

        • They can then listen  and receive connections destined for the legitimate IP.

      • DNS spoofing

        • The attacker tricks the client into thinking api.myserver.com  resolves to the attacker’s IP.

        • The client then connects to the attacker.

        • This attack depends on name resolution control, not listen  directly.

      • BGP hijacking (Internet level)

        • Much rarer and more complex.

        • The attacker announces false routes on the Internet backbone, intercepting traffic to the server’s IP.

        • Applicable only in highly sophisticated attacks.

Head-of-line Blocking

  • TCP ensures packets arrive in order .

  • If a packet is lost, all subsequent packets must wait for retransmission before delivery to the application. This creates a bottleneck, as correctly received packets get "stuck" until the lost packet is received.

  • Example :

    • You send 3 packets: P1 , P2 , P3 .

    • The receiver gets P1  and P3 , but P2  is lost.

    • TCP waits for retransmission of P2  before releasing P3  to the application.

    • Result: Unnecessary delay , because P3  could have been processed earlier.

  • This blocking is one reason TCP can be slow for games and other low-latency applications.